<template>
	<el-table v-bind="$attrs" @row-click="rowClick" :element-loading-text="elementLoadingText"
		:element-loading-spinner="elementLoadingSpinner" :element-loading-background="elementLoadingBackground"
		:element-loading-svg="elementLoadingSvg" :element-loading-svg-view-box="elementLoadingSvgViewBox"
		v-loading="isLoading" :data="tableData">
		<template v-for="(item, index) in tableOptions" :key="index">
			<el-table-column :width="item.width" :align="item.align" :prop="item.prop" :label="item.label">
				<template #default="scope">
					<template v-if="scope.row.isEditRow">
						<el-input size="small" v-model="scope.row[item.prop]"></el-input>
					</template>
					<template v-else>
						<template v-if="(scope.$index + scope.column.id) === currentEdit">
							<div style="display: flex;">
								<el-input v-model="scope.row[item.prop]" size="small"></el-input>
								<div @click.stop="clickEditCell">
									<slot :scope="scope" v-if="$slots.editCell" name="editCell"></slot>
									<div v-else class="icons">
										<el-icon-check @click="check(scope)" class="check"></el-icon-check>
										<el-icon-close @click="close(scope)" class="close"></el-icon-close>
									</div>
								</div>
							</div>
						</template>
						<template v-else>
							<slot v-if="item.slot" :name="item.slot" :scope="scope"></slot>
							<span v-else>{{scope.row[item.prop]}}</span>
							<component @click.stop="clickEdit(scope)" class="edit" v-if="item.editable"
								:is="`el-icon-${toLine(props.editIcon)}`"></component>
						</template>
					</template>
				</template>
			</el-table-column>
		</template>
		<el-table-column v-if="actionOptions" :width="actionOptions.width" :align="actionOptions.align"
			:label="actionOptions.label">
			<template #default="scope">
				<slot name="editRow" v-if="scope.row.isEditRow"></slot>
				<slot name="action" v-else :scope="scope"></slot>
			</template>
		</el-table-column>
	</el-table>

	<div v-if="pagination && !isLoading" class="pagination" :style="{justifyContent: paginationAlignJustify}">
		<el-pagination :currentPage="currentPage" :page-size="pageSize" :page-sizes="pageSizes"
			layout="total, sizes, prev, pager, next, jumper" :total="total" @size-change="handleSizeChange"
			@current-change="handleCurrentChange" />
	</div>
</template>

<script lang="ts" setup name="xtable">
	import {
		toLine
	} from '@/utils/main.ts'
	import cloneDeep from 'lodash/cloneDeep'

	import {
		ref,
		computed,
		onMounted,
		watch
	} from 'vue'

	let props = defineProps({
		options: {
			type: Array,
			required: true
		},

		data: {
			type: Array,
			required: true
		},

		elementLoadingText: {
			type: String
		},

		elementLoadingSpinner: {
			type: String
		},

		elementLoadingBackground: {
			type: String
		},

		elementLoadingSvg: {
			type: String
		},

		elementLoadingSvgViewBox: {
			type: String
		},

		editIcon: {
			type: String,
			default: 'edit'
		},

		isEditRow: {
			type: Boolean,
			default: false
		},

		editRowIndex: {
			type: String,
			default: ''
		},

		currentPage: {
			type: Number,
			default: 1
		},

		pageSizes: {
			type: Array,
			default: [5, 10, 15]
		},

		pageSize: {
			type: Number,
			default: 5
		},

		total: {
			type: Number
		},

		pagination: {
			type: Boolean,
			default: false
		},

		paginationAlign: {
			type: String,
			default: 'left'
		}
	})

	let tableOptions = computed(() => props.options.filter(item => item.action !== true))
	let actionOptions = computed(() => props.options.find(item => item.action))
	let isLoading = computed(() => !props.data || !props.data.length)

	let paginationAlignJustify = computed(() => {
		if (props.paginationAlign === 'left') return 'flex-start'
		else if (props.paginationAlign === 'center') return 'center'
		else return 'flex-end'
	})

	let currentEdit = ref('')

	let handleSizeChange = val => {
		
		emits('sizeChange', val)
	}

	let handleCurrentChange = val => {
		emits('currentChange', val)
	}

	// 不能直接修改父组件传递过来的数据，所以先做一次拷贝
	let tableData = ref(cloneDeep(props.data))
	let cloneEditRowIndex = ref(cloneDeep(props.editRowIndex))

	watch(() => props.data, val => {
		tableData.value = cloneDeep(val)

		tableData.value.map(item => {
			item.isEditRow = false
		})
	}, {
		deep: true
	})

	// props.editRowIndex -- edit/delete, 监听点击的按钮是编辑还是删除
	watch(() => props.editRowIndex, val => {
		if (val) {
			cloneEditRowIndex.value = cloneDeep(val)
		}
	})

	onMounted(() => {
		tableData.value.map(item => {
			item.isEditRow = false
		})
	})

	// 因为是插槽传递过来的按钮，所以无法判断是否被点击了
	let rowClick = (row, column) => {
		if (column.label === actionOptions.value.label) {
			// 代表点击的是操作项,且是可点击的（编辑/删除）按钮
			if (props.isEditRow && cloneEditRowIndex.value === props.editRowIndex) {
				// 改变这一行的状态
				if (cloneEditRowIndex.value === 'edit') {
					row.isEditRow = !row.isEditRow
				}
				// 重置其他数据的isEditRow
				tableData.value.map(item => {
					if (item !== row) item.isEditRow = false
				})
				// 重置按钮的标识editRowIndex
				if (!row.isEditRow) {
					emits('update:editRowIndex', '')
				}
			}
		}
	}

	let clickEdit = scope => {
		currentEdit.value = scope.$index + scope.column.id
	}

	let emits = defineEmits(['cancel', 'confirm', 'update:editRowIndex', 'sizeChange', 'currentChange'])

	let check = scope => {
		emits('confirm', scope)
	}

	let close = scope => {
		emits('cancel', scope)
	}

	let clickEditCell = () => {
		currentEdit.value = ''
	}
</script>

<style lang="scss" scoped>
	.edit {
		position: relative;
		top: 5px;
		left: 4px;
	}

	.icons {
		display: flex;
		position: relative;
		top: 5px;
		margin-left: 6px;
		cursor: pointer;

		.check {
			color: red;
		}

		.close {
			color: green;
		}
	}

	.pagination {
		display: flex;
		align-items: center;
		margin-top: 16px;
	}
</style>
